<?php
// @formatter:off
/**
 * @file WCConnection.php
 * @author Alejandro Dario Simi
 * @date $Date: 2013-05-19 06:39:24 +0000 (Sun, 19 May 2013) $
 *
 * $Id: WCConnection.php 65 2013-05-19 06:39:24Z daemonraco@gmail.com $
 * $URL: http://wcomix.googlecode.com/svn/tags/wcomix-1.0-BETA1/includes/db/WCConnection.php $
 */
// @formatter:on

/**
 * @class WCConnection
 * This class is the interface used to interact with the database, from connecting
 * to performing queries.
 */
class WCConnection {
	/**
	 * @var WCConnection Pointer to the singleton instance.
	 */
	protected static $_Instance;
	/**
	 * @var PDO This is the database connection object.
	 */
	protected $_dbLink = null;
	/**
	 * @var PDOStatement[string] This is a list of prepared statements. It
	 * used to avoid preparing the same statement more than once and save the
	 * time taken in build a query.
	 */
	protected $_prepatedStmts = array();

	/**
	 * This is the class basic constructor.
	 */
	protected function __construct() {
		//
		// Loading global database settings.
		global $wcDatabaseAccess;
		//
		// Attempting to connect.
		try {
			//
			// Creating the connection object.
			//
			// @note: by now, it only works with MySQL.
			$this->_dbLink = new PDO("mysql:host={$wcDatabaseAccess['server']};dbname={$wcDatabaseAccess['database']}", $wcDatabaseAccess['username'], $wcDatabaseAccess['password']);
		} catch(PDOException $e) {
			//
			// If there is a database connection exception, it is
			// caught and a user exception is raised.
			trigger_error(__CLASS__.": Unable to connect to database.", E_USER_ERROR);
		}
		//
		// For security reasons, once the connection to the database is
		// established the password is removed with the exception of the
		// installation process that my needed for other reasons.
		if(!defined("WC_NOT_INSTALLED")) {
			//
			// Cleaning databse password..
			$wcDatabaseAccess['password'] = false;
		}
	}
	/**
	 * Prevent users to clone the instance.
	 */
	public function __clone() {
		trigger_error(__CLASS__.": Clone is not allowed.", E_USER_ERROR);
	}
	//
	// Public methods.
	/**
	 * This method is similar than 'query()', but it uses the method
	 * 'PDO::exec()'.
	 *
	 * @param string $query SQL query to be executed.
	 * @param boolean $dieOnError When true, if there were any problem
	 * performing the query, it raises an exception.
	 * @return int Returns the number of rows that were modified or deleted by
	 * the SQL statement you issued. If no rows were affected, returns 0
	 */
	public function exec($query, $dieOnError = true) {
		//
		// Setting the default value to be returned.
		$result = false;
		try {
			//
			// Attempting to execute the requested query.
			$result = $this->_dbLink->exec($query);
		} catch(PDOException $e) {
			//
			// If there were any issue with the query and the result
			// is set to false.
			$result = false;
		}
		//
		// Checking that there where no errors, and if there were and it's
		// specified, and exception is raised.
		if($dieOnError && $result === false) {
			$info = $this->_dbLink->errorInfo();
			trigger_error(__CLASS__.": Unable to run query: {$query}. MySQL Error: [{$this->_dbLink->errorCode()}] {$info[0]}-{$info[1]}-{$info[2]}", E_USER_ERROR);
		}
		//
		// Returning the resulting statement.
		return $result;
	}
	/**
	 * This method allows to get a statement that is being held by the class.
	 *
	 * @param string $id Identificator of the statement to get.
	 * @return boolean Returns the requested statement.
	 */
	public function & get($id) {
		//
		// Checking that the statement exists in the list.
		if(!$this->has($id)) {
			//
			// If the statement is not in the list, an exception is
			// raised.
			trigger_error(__CLASS__.": Statement '{$id}' not yet created", E_USER_ERROR);
		}
		//
		// Returning the requested statement.
		return $this->_prepatedStmts[$id];
	}
	/**
	 * This method checks if a prepared statement is already being held by
	 * this class.
	 *
	 * @param string $id Identificator of the statement to check.
	 * @return boolean Returns true when the statement is being held.
	 */
	public function has($id) {
		//
		// Checking if the id is set in the list if statements.
		return isset($this->_prepatedStmts[$id]);
	}
	/**
	 * This method allows to get the last id used by an INSERT operation.
	 *
	 * @param string $name Name of the sequence object from which the ID
	 * should be returned.
	 * @return int Returns the last inserted id.
	 */
	public function lastInsertId($name = null) {
		return $this->_dbLink->lastInsertId($name);
	}
	/**
	 * This method allows to get the database connection object.
	 *
	 * @return PDO Returns a connection pointer.
	 */
	public function & link() {
		return $this->_dbLink;
	}
	/**
	 * This method allows to add a new statement to the internal list.
	 *
	 * @param string $id Identificator to associate with the statement.
	 * @param string $query SQL query to use for the statement creation.
	 * @return PDOStatement Returns a pointer to the new statement.
	 */
	public function & prepare($id, $query) {
		//
		// Checking that the requested id wasn't used before. If it was,
		// it won't be replaced.
		if(!$this->has($id)) {
			//
			// Preparing the new statement.
			$this->_prepatedStmts[$id] = $this->_dbLink->prepare($query);
			//
			// Setting the statement to return results as associative
			// arrays.
			$this->_prepatedStmts[$id]->setFetchMode(PDO::FETCH_ASSOC);
		}
		//
		// Returning the statement with the requested id.
		return $this->_prepatedStmts[$id];
	}
	/**
	 * This method allows to directly execute a query on the database.
	 *
	 * @param string $query SQL query to be executed.
	 * @param boolean $dieOnError When true, if there were any problem
	 * performing the query, it raises an exception.
	 * @return PDOStatement Returning the statement generated by the query. On
	 * error, returns false.
	 */
	public function query($query, $dieOnError = true) {
		//
		// Setting the default value to be returned.
		$result = false;
		try {
			//
			// Attempting to execute the requested query.
			$result = $this->_dbLink->query($query, PDO::FETCH_ASSOC);
		} catch(PDOException $e) {
			//
			// If there were any issue with the query and the result
			// is set to false.
			$result = false;
		}
		//
		// Checking that there where no errors, and if there were and it's
		// specified, and exception is raised.
		if($dieOnError && $result === false) {
			$info = $this->_dbLink->errorInfo();
			trigger_error(__CLASS__.": Unable to run query: {$query}. MySQL Error: [{$this->_dbLink->errorCode()}] {$info[0]}-{$info[1]}-{$info[2]}", E_USER_ERROR);
		}
		//
		// Returning the resulting statement.
		return $result;
	}
	//
	// Public class methods.
	/**
	 * This class method allows to get the sole instance of this holder.
	 *
	 * @return WCConnection Returns the singleton instance of this
	 * class.
	 */
	public static function Instance() {
		//
		// Checking if there's no instance yet.
		if(!isset(self::$_Instance)) {
			$c = __CLASS__;
			//
			// Creating the sole instance.
			self::$_Instance = new $c;
		}
		//
		// Returning the class instance.
		return self::$_Instance;
	}
};
?>